package com.example.glideprogressiveloadimg

import android.annotation.SuppressLint
import android.os.Build
import android.util.Log
import androidx.core.util.Preconditions
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.HttpException
import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.util.ContentLengthInputStream
import okhttp3.Call
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.IOException
import java.io.InputStream
import java.util.logging.Logger

class OkHttpStreamFetcher : DataFetcher<InputStream>, okhttp3.Callback{

    val TAG= OkHttpStreamFetcher::class.java.simpleName

    var client : Call.Factory?=null

    var url : GlideUrl?=null

    var stream:InputStream?=null

    var responseBody : ResponseBody?= null

    var call : Call?=null

    var callback : DataFetcher.DataCallback<in InputStream>?=null

    constructor(client: Call.Factory?, url : GlideUrl?) {
        this.client = client
        this.url = url
    }

    override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
        if (url == null ) return
        if (client == null) return
        Log.d(TAG, "loadData :: ")
        val requestBuilder = Request.Builder().url(url.toString())
        for (headerEntry : Map.Entry<String, String> in url!!.headers.entries) {
            val key= headerEntry.key
            requestBuilder.addHeader(key, headerEntry.value)
        }

        val request = requestBuilder.build()
        this.callback = callback

        call = client!!.newCall(request)
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O) {
            call!!.enqueue(this)
        } else {
            try {
                onResponse(call!!, call!!.execute())
            }catch (ex:IOException) {
                ex.printStackTrace()
            }catch (e : ClassCastException) {
                onFailure(call!!, IOException("Workaround for framework bug on O", e))
            }
        }
    }

    override fun onFailure(call: Call, e: IOException) {
        Log.e(TAG, "onFailure :: OKHttp failed to obtain result, $e")
        callback!!.onLoadFailed(e)
    }

    //    @SuppressLint("RestrictedApi")
    override fun onResponse(call: Call, response: Response) {
        responseBody = response.body()
        if (response.isSuccessful) {
//            Preconditions.checkNotNull(responseBody).contentLength()
            if (responseBody == null) return
            val contentLength = responseBody!!.contentLength()
            Log.d(TAG, "contentLength = $contentLength")
            stream = ContentLengthInputStream.obtain(responseBody!!.byteStream(), contentLength)
            callback!!.onDataReady(stream!!)
        }else {
            callback!!.onLoadFailed(HttpException(response.message(), response.code()))
        }
    }

    override fun cleanup() {
        stream?.close()
        responseBody?.close()
        callback = null
    }

    override fun cancel() {
        call?.cancel()
    }

    override fun getDataClass(): Class<InputStream> {
        return InputStream::class.java
    }

    override fun getDataSource(): DataSource {
        return DataSource.REMOTE
    }

}